home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / objam01.lha / objam / objc / archive.c next >
Encoding:
C/C++ Source or Header  |  1995-02-14  |  33.3 KB  |  1,340 lines

  1. /*
  2. ** ObjectiveAmiga: Archiving
  3. ** See GNU:lib/libobjam/ReadMe for details
  4. */
  5.  
  6.  
  7. #include "runtime.h"
  8. #include "typedstream.h"
  9. #include "hash.h"
  10.  
  11. #include <proto/dos.h>
  12.  
  13.  
  14. /*
  15. ** Local definitions
  16. */
  17.  
  18. #define OBJC_TYPED_STREAM_VERSION 0x01
  19.  
  20. #define OBJC_MANAGED_STREAM  0x01
  21. #define OBJC_FILE_STREAM     0x02
  22. #define OBJC_MEMORY_STREAM   0x04
  23.  
  24. /* opcode masks */
  25. #define _B_VALUE   0x1fU
  26. #define _B_CODE    0xe0U
  27. #define _B_SIGN    0x10U
  28. #define _B_NUMBER  0x0fU
  29.  
  30. /* standard opcodes */
  31. #define _B_INVALID 0x00U
  32. #define _B_SINT    0x20U
  33. #define _B_NINT    0x40U
  34. #define _B_SSTR    0x60U
  35. #define _B_NSTR    0x80U
  36. #define _B_RCOMM   0xa0U
  37. #define _B_UCOMM   0xc0U
  38. #define _B_EXT     0xe0U
  39.  
  40. /* eXtension opcodes */
  41. #define _BX_OBJECT  0x00U
  42. #define _BX_CLASS   0x01U
  43. #define _BX_SEL     0x02U
  44. #define _BX_OBJREF  0x03U
  45. #define _BX_OBJROOT 0x04U
  46. #define _BX_EXT     0x1fU
  47.  
  48.  
  49. /*
  50. ** Declare some functions
  51. */
  52.  
  53. static int objc_read_class (struct objc_typed_stream* stream, OCClass** class);
  54. static int objc_write_use_common (struct objc_typed_stream* stream, unsigned int key);
  55. static int objc_write_register_common (struct objc_typed_stream* stream, unsigned int key);
  56. static int objc_write_class (struct objc_typed_stream* stream, struct objc_class* class);
  57. static const char*__objc_skip_type (const char* type);
  58. static void __objc_finish_write_root_object(struct objc_typed_stream*);
  59. static void __objc_finish_read_root_object(struct objc_typed_stream*);
  60.  
  61.  
  62. /*
  63. ** Auxiliary functions
  64. */
  65.  
  66. static __inline__ int
  67. __objc_code_unsigned_char (unsigned char* buf, unsigned char val)
  68. {
  69.   if ((val&_B_VALUE) == val)
  70.     { buf[0] = val|_B_SINT; return 1; }
  71.   else
  72.     { buf[0] = _B_NINT|0x01; buf[1] = val; return 2; }
  73. }
  74.  
  75.  
  76. int
  77. objc_write_unsigned_char (struct objc_typed_stream* stream, unsigned char value)
  78. {
  79.   unsigned char buf[sizeof (unsigned char)+1];
  80.   int len = __objc_code_unsigned_char (buf, value);
  81.   return (*stream->write)(stream->physical, buf, len);
  82. }
  83.  
  84.  
  85. static __inline__ int
  86. __objc_code_char (unsigned char* buf, char val)
  87. {
  88.   if (val >= 0) return __objc_code_unsigned_char (buf, val);
  89.   else { buf[0] = _B_NINT|_B_SIGN|0x01; buf[1] = -val; return 2; }
  90. }
  91.  
  92.  
  93. int
  94. objc_write_char (struct objc_typed_stream* stream, char value)
  95. {
  96.   unsigned char buf[sizeof (char)+1];
  97.   int len = __objc_code_char (buf, value);
  98.   return (*stream->write)(stream->physical, buf, len);
  99. }
  100.  
  101.  
  102. static __inline__ int
  103. __objc_code_unsigned_short (unsigned char* buf, unsigned short val)
  104. {
  105.   if (val <= 0xffU) return __objc_code_unsigned_char (buf, val);
  106.   else 
  107.   {
  108.     buf[0] = _B_NINT|0x02;
  109.     buf[1] = val/0x100;
  110.     buf[2] = val%0x100;
  111.     return 3;
  112.   }
  113. }
  114.  
  115.  
  116. int
  117. objc_write_unsigned_short (struct objc_typed_stream* stream, unsigned short value)
  118. {
  119.   unsigned char buf[sizeof (unsigned short)+1];
  120.   int len = __objc_code_unsigned_short (buf, value);
  121.   return (*stream->write)(stream->physical, buf, len);
  122. }
  123.  
  124.       
  125. static __inline__ int
  126. __objc_code_short (unsigned char* buf, short val)
  127. {
  128.   if (val > 0) return __objc_code_unsigned_short (buf, val);
  129.   if (val > -0x7f) /* val > -128 */ return __objc_code_char (buf, val);
  130.   else 
  131.   {
  132.     int len = __objc_code_unsigned_short (buf, -val);
  133.     buf[0] |= _B_SIGN;
  134.     return len;
  135.   }
  136. }
  137.  
  138.  
  139. int
  140. objc_write_short (struct objc_typed_stream* stream, short value)
  141. {
  142.   unsigned char buf[sizeof (short)+1];
  143.   int len = __objc_code_short (buf, value);
  144.   return (*stream->write)(stream->physical, buf, len);
  145. }
  146.  
  147.       
  148. static __inline__ int
  149. __objc_code_unsigned_int (unsigned char* buf, unsigned int val)
  150. {
  151.   if (val < 0x10000) return __objc_code_unsigned_short (buf, val%0x10000);
  152.   else if (val < 0x1000000)
  153.   {
  154.     buf[0] = _B_NINT|3;
  155.     buf[1] = val/0x10000;
  156.     buf[2] = (val%0x10000)/0x100;
  157.     buf[3] = val%0x100;
  158.     return 4;
  159.   }
  160.   else 
  161.   {
  162.     buf[0] = _B_NINT|4;
  163.     buf[1] = val/0x1000000;
  164.     buf[2] = (val%0x1000000)/0x10000;
  165.     buf[3] = (val%0x10000)/0x100;
  166.     buf[4] = val%0x100;
  167.     return 5;
  168.   }
  169. }
  170.  
  171.  
  172. int
  173. objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value)
  174. {
  175.   unsigned char buf[sizeof(unsigned int)+1];
  176.   int len = __objc_code_unsigned_int (buf, value);
  177.   return (*stream->write)(stream->physical, buf, len);
  178. }
  179.  
  180.  
  181. static __inline__ int
  182. __objc_code_int (unsigned char* buf, int val)
  183. {
  184.   if (val >= 0) return __objc_code_unsigned_int (buf, val);
  185.   if (val > -0x7f) return __objc_code_char (buf, val);
  186.   else 
  187.   {
  188.     int len = __objc_code_unsigned_int (buf, -val);
  189.     buf[0] |= _B_SIGN;
  190.     return len;
  191.   }
  192. }
  193.  
  194.  
  195. int
  196. objc_write_int (struct objc_typed_stream* stream, int value)
  197. {
  198.   unsigned char buf[sizeof(int)+1];
  199.   int len = __objc_code_int (buf, value);
  200.   return (*stream->write)(stream->physical, buf, len);
  201. }
  202.  
  203.  
  204. int
  205. objc_write_string (struct objc_typed_stream* stream, const unsigned char* string, unsigned int nbytes)
  206. {
  207.   unsigned char buf[sizeof(unsigned int)+1];
  208.   int len = __objc_code_unsigned_int (buf, nbytes);
  209.   
  210.   if ((buf[0]&_B_CODE) == _B_SINT) buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
  211.   else /* _B_NINT */ buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
  212.  
  213.   if ((*stream->write)(stream->physical, buf, len) != 0)
  214.     return (*stream->write)(stream->physical, string, nbytes);
  215.   else return 0;
  216. }
  217.  
  218.  
  219. int
  220. objc_write_string_atomic (struct objc_typed_stream* stream, unsigned char* string, unsigned int nbytes)
  221. {
  222.   unsigned int key;
  223.   if ((key = (unsigned int)hash_value_for_key (stream->stream_table, string)))
  224.     return objc_write_use_common (stream, key);
  225.   else
  226.   {
  227.     int length;
  228.     hash_add (&stream->stream_table, (void*)key=(unsigned int)string, string);
  229.     if ((length = objc_write_register_common (stream, key)))
  230.       return objc_write_string (stream, string, nbytes);
  231.     return length;
  232.   }
  233. }
  234.  
  235.  
  236. static int
  237. objc_write_register_common (struct objc_typed_stream* stream, unsigned int key)
  238. {
  239.   unsigned char buf[sizeof (unsigned int)+2];
  240.   int len = __objc_code_unsigned_int (buf+1, key);
  241.   if (len == 1)
  242.   {
  243.     buf[0] = _B_RCOMM|0x01;
  244.     buf[1] &= _B_VALUE;
  245.     return (*stream->write)(stream->physical, buf, len+1);
  246.   }
  247.   else
  248.   {
  249.     buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
  250.     return (*stream->write)(stream->physical, buf+1, len);
  251.   }
  252. }
  253.  
  254.  
  255. static int
  256. objc_write_use_common (struct objc_typed_stream* stream, unsigned int key)
  257. {
  258.   unsigned char buf[sizeof (unsigned int)+2];
  259.   int len = __objc_code_unsigned_int (buf+1, key);
  260.   if (len == 1)
  261.   {
  262.     buf[0] = _B_UCOMM|0x01;
  263.     buf[1] &= _B_VALUE;
  264.     return (*stream->write)(stream->physical, buf, 2);
  265.   }
  266.   else
  267.   {
  268.     buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
  269.     return (*stream->write)(stream->physical, buf+1, len);
  270.   }
  271. }
  272.  
  273.  
  274. static __inline__ int
  275. __objc_write_extension (struct objc_typed_stream* stream, unsigned char code)
  276. {
  277.   if (code <= _B_VALUE)
  278.   {
  279.     unsigned char buf = code|_B_EXT;
  280.     return (*stream->write)(stream->physical, &buf, 1);
  281.   }
  282.   else abort();
  283. }
  284.  
  285.  
  286. __inline__ int
  287. __objc_write_object (struct objc_typed_stream* stream, id object)
  288. {
  289.   unsigned char buf = '\0';
  290.   SEL write_sel = sel_get_uid ("write:");
  291.   if (object)
  292.   {
  293.     __objc_write_extension (stream, _BX_OBJECT);
  294.     objc_write_class (stream, object->class_pointer);
  295.     (*objc_msg_lookup(object, write_sel))(object, write_sel, stream);
  296.     return (*stream->write)(stream->physical, &buf, 1);
  297.   }
  298.   else return objc_write_use_common(stream, 0);
  299. }
  300.  
  301.  
  302. int 
  303. objc_write_object_reference (struct objc_typed_stream* stream, id object)
  304. {
  305.   unsigned int key;
  306.   if ((key = (unsigned int)hash_value_for_key (stream->object_table, object)))
  307.     return objc_write_use_common (stream, key);
  308.  
  309.   __objc_write_extension (stream, _BX_OBJREF);
  310.   return objc_write_unsigned_int (stream, (unsigned int)object);
  311. }
  312.  
  313.  
  314. int 
  315. objc_write_root_object (struct objc_typed_stream* stream, id object)
  316. {
  317.   int len;
  318.   if (stream->writing_root_p)
  319.     __objc_archiving_fatal ("Function objc_write_root_object() called recursively",0);
  320.   else
  321.   {
  322.     stream->writing_root_p = 1;
  323.     __objc_write_extension (stream, _BX_OBJROOT);
  324.     if((len = objc_write_object (stream, object))) __objc_finish_write_root_object(stream);
  325.     stream->writing_root_p = 0;
  326.   }
  327.   return len;
  328. }
  329.  
  330.  
  331. int 
  332. objc_write_object (struct objc_typed_stream* stream, id object)
  333. {
  334.   unsigned int key;
  335.   if ((key = (unsigned int)hash_value_for_key (stream->object_table, object)))
  336.     return objc_write_use_common (stream, key);
  337.   else if (object == nil) return objc_write_use_common(stream, 0);
  338.   else
  339.   {
  340.     int length;
  341.     hash_add (&stream->object_table, (void*)key=(unsigned int)object, object);
  342.     if ((length = objc_write_register_common (stream, key))) return __objc_write_object (stream, object);
  343.     return length;
  344.   }
  345. }
  346.  
  347.  
  348. __inline__ int
  349. __objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
  350. {
  351.   __objc_write_extension (stream, _BX_CLASS);
  352.   objc_write_string_atomic(stream, (char*)class->name, strlen((char*)class->name));
  353.   return objc_write_unsigned_int (stream, CLS_GETNUMBER(class));
  354. }
  355.  
  356.  
  357. static int 
  358. objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
  359. {
  360.   unsigned int key;
  361.   if ((key = (unsigned int)hash_value_for_key (stream->stream_table, class)))
  362.     return objc_write_use_common (stream, key);
  363.   else
  364.   {
  365.     int length;
  366.     hash_add (&stream->stream_table, (void*)key=(unsigned int)class, class);
  367.     if ((length = objc_write_register_common (stream, key))) return __objc_write_class (stream, class);
  368.     return length;
  369.   }
  370. }
  371.  
  372.  
  373. __inline__ int 
  374. __objc_write_selector (struct objc_typed_stream* stream, SEL selector)
  375. {
  376.   const char* sel_name = sel_get_name (selector);
  377.   __objc_write_extension (stream, _BX_SEL);
  378.   return objc_write_string (stream, sel_name, strlen ((char*)sel_name));
  379. }
  380.  
  381.  
  382. int 
  383. objc_write_selector (struct objc_typed_stream* stream, SEL selector)
  384. {
  385.   const char* sel_name = sel_get_name (selector);
  386.   unsigned int key;
  387.   if ((key = (unsigned int)hash_value_for_key (stream->stream_table, sel_name)))
  388.     return objc_write_use_common (stream, key);
  389.   else
  390.   {
  391.     int length;
  392.     hash_add (&stream->stream_table, (void*)key=(unsigned int)sel_name, (char*)sel_name);
  393.     if ((length = objc_write_register_common (stream, key))) return __objc_write_selector (stream, selector);
  394.     return length;
  395.   }
  396. }
  397.  
  398.  
  399. /*
  400. ** Read operations 
  401. */
  402.  
  403. __inline__ int
  404. objc_read_char (struct objc_typed_stream* stream, char* val)
  405. {
  406.   unsigned char buf;
  407.   int len;
  408.   len = (*stream->read)(stream->physical, &buf, 1);
  409.   if (len != 0)
  410.   {
  411.     if ((buf & _B_CODE) == _B_SINT) (*val) = (buf & _B_VALUE);
  412.     else if ((buf & _B_NUMBER) == 1)
  413.     {
  414.       len = (*stream->read)(stream->physical, val, 1);
  415.       if (buf&_B_SIGN) (*val) = -1*(*val);
  416.     }
  417.     else __objc_archiving_fatal("Expected 8bit signed int, got %dbit int", (int)(buf&_B_NUMBER)*8);
  418.   }
  419.   return len;
  420. }
  421.  
  422.  
  423. __inline__ int
  424. objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val)
  425. {
  426.   unsigned char buf;
  427.   int len;
  428.   if ((len = (*stream->read)(stream->physical, &buf, 1)))
  429.   {
  430.     if ((buf & _B_CODE) == _B_SINT) (*val) = (buf & _B_VALUE);
  431.     else if ((buf & _B_NUMBER) == 1) len = (*stream->read)(stream->physical, val, 1);
  432.     else __objc_archiving_fatal("Expected 8bit unsigned int, got %dbit int", (int)(buf&_B_NUMBER)*8);
  433.   }
  434.   return len;
  435. }
  436.  
  437. __inline__ int
  438. objc_read_short (struct objc_typed_stream* stream, short* value)
  439. {
  440.   unsigned char buf[sizeof(short)+1];
  441.   int len;
  442.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  443.   {
  444.     if ((buf[0] & _B_CODE) == _B_SINT) (*value) = (buf[0] & _B_VALUE);
  445.     else
  446.     {
  447.       int pos = 1;
  448.       int nbytes = buf[0] & _B_NUMBER;
  449.       if (nbytes > sizeof (short)) __objc_archiving_fatal("Expected short, got bigger (%dbits)", nbytes*8);
  450.       len = (*stream->read)(stream->physical, buf+1, nbytes);
  451.       (*value) = 0;
  452.       while (pos <= nbytes) (*value) = ((*value)*0x100) + buf[pos++];
  453.       if (buf[0] & _B_SIGN) (*value) = -(*value);
  454.     }
  455.   }
  456.   return len;
  457. }
  458.  
  459. __inline__ int
  460. objc_read_unsigned_short (struct objc_typed_stream* stream, unsigned short* value)
  461. {
  462.   unsigned char buf[sizeof(unsigned short)+1];
  463.   int len;
  464.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  465.   {
  466.     if ((buf[0] & _B_CODE) == _B_SINT) (*value) = (buf[0] & _B_VALUE);
  467.     else
  468.     {
  469.       int pos = 1;
  470.       int nbytes = buf[0] & _B_NUMBER;
  471.       if (nbytes > sizeof (short)) __objc_archiving_fatal("Expected short, got int or bigger",0);
  472.       len = (*stream->read)(stream->physical, buf+1, nbytes);
  473.       (*value) = 0;
  474.       while (pos <= nbytes) (*value) = ((*value)*0x100) + buf[pos++];
  475.     }
  476.   }
  477.   return len;
  478. }
  479.  
  480.  
  481. __inline__ int
  482. objc_read_int (struct objc_typed_stream* stream, int* value)
  483. {
  484.   unsigned char buf[sizeof(int)+1];
  485.   int len;
  486.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  487.   {
  488.     if ((buf[0] & _B_CODE) == _B_SINT) (*value) = (buf[0] & _B_VALUE);
  489.     else
  490.     {
  491.       int pos = 1;
  492.       int nbytes = buf[0] & _B_NUMBER;
  493.       if (nbytes > sizeof (int)) __objc_archiving_fatal("Expected int, got bigger",0);
  494.       len = (*stream->read)(stream->physical, buf+1, nbytes);
  495.       (*value) = 0;
  496.       while (pos <= nbytes) (*value) = ((*value)*0x100) + buf[pos++];
  497.       if (buf[0] & _B_SIGN) (*value) = -(*value);
  498.     }
  499.   }
  500.   return len;
  501. }
  502.  
  503. __inline__ int
  504. __objc_read_nbyte_uint (struct objc_typed_stream* stream, unsigned int nbytes, unsigned int* val)
  505. {
  506.   int len, pos = 0;
  507.   unsigned char buf[sizeof(unsigned int)+1];
  508.  
  509.   if (nbytes > sizeof (int)) __objc_archiving_fatal("Expected int, got bigger",0);
  510.  
  511.   len = (*stream->read)(stream->physical, buf, nbytes);
  512.   (*val) = 0;
  513.   while (pos < nbytes) (*val) = ((*val)*0x100) + buf[pos++];
  514.   return len;
  515. }
  516.   
  517.  
  518. __inline__ int
  519. objc_read_unsigned_int (struct objc_typed_stream* stream, unsigned int* value)
  520. {
  521.   unsigned char buf[sizeof(unsigned int)+1];
  522.   int len;
  523.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  524.   {
  525.     if ((buf[0] & _B_CODE) == _B_SINT) (*value) = (buf[0] & _B_VALUE);
  526.     else len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
  527.   }
  528.   return len;
  529. }
  530.  
  531. __inline__ int
  532. objc_read_string (struct objc_typed_stream* stream, char** string)
  533. {
  534.   unsigned char buf[sizeof(unsigned int)+1];
  535.   int len;
  536.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  537.   {
  538.     unsigned int key = 0;
  539.  
  540.     if ((buf[0]&_B_CODE) == _B_RCOMM)    /* register following */
  541.     {
  542.       len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
  543.       len = (*stream->read)(stream->physical, buf, 1);
  544.     }
  545.  
  546.     switch (buf[0]&_B_CODE)
  547.     {
  548.       case _B_SSTR:
  549.     {
  550.       int length = buf[0]&_B_VALUE;
  551.       (*string) = (char*)__objc_xmalloc(length+1);
  552.       if (key) hash_add (&stream->stream_table, (void*)key, *string);
  553.       len = (*stream->read)(stream->physical, *string, length);
  554.       (*string)[length] = '\0';
  555.     }
  556.     break;
  557.  
  558.       case _B_UCOMM:
  559.     {
  560.       char *tmp;
  561.       len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), &key);
  562.       tmp = hash_value_for_key (stream->stream_table, (void*)key);
  563.       *string = __objc_xmalloc (strlen (tmp) + 1);
  564.       strcpy (*string, tmp);
  565.     }
  566.     break;
  567.  
  568.       case _B_NSTR:
  569.     {
  570.       unsigned int nbytes = buf[0]&_B_VALUE;
  571.       len = __objc_read_nbyte_uint(stream, nbytes, &nbytes);
  572.       if (len)
  573.       {
  574.         (*string) = (char*)__objc_xmalloc(nbytes+1);
  575.         if (key) hash_add (&stream->stream_table, (void*)key, *string);
  576.         len = (*stream->read)(stream->physical, *string, nbytes);
  577.         (*string)[nbytes] = '\0';
  578.       }
  579.     }
  580.     break;
  581.     
  582.       default:
  583.     __objc_archiving_fatal("Expected string, got opcode %c\n", (buf[0]&_B_CODE));
  584.     }
  585.   }
  586.  
  587.   return len;
  588. }
  589.  
  590.  
  591. int
  592. objc_read_object (struct objc_typed_stream* stream, id* object)
  593. {
  594.   unsigned char buf[sizeof (unsigned int)];
  595.   int len;
  596.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  597.   {
  598.     SEL read_sel = sel_get_uid ("read:");
  599.     unsigned int key = 0;
  600.  
  601.     if ((buf[0]&_B_CODE) == _B_RCOMM)    /* register common */
  602.     {
  603.       len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
  604.       len = (*stream->read)(stream->physical, buf, 1);
  605.     }
  606.  
  607.     if (buf[0] == (_B_EXT | _BX_OBJECT))
  608.     {
  609.       OCClass* class;
  610.  
  611.       /* get class */
  612.       len = objc_read_class (stream, &class);
  613.  
  614.       /* create instance */
  615.       (*object) = class_create_instance(class);
  616.  
  617.       /* register? */
  618.       if (key) hash_add (&stream->object_table, (void*)key, *object);
  619.  
  620.       /* send -read: */
  621.       if (__objc_responds_to (*object, read_sel)) (*get_imp(class, read_sel))(*object, read_sel, stream);
  622.  
  623.       /* check null-byte */
  624.       len = (*stream->read)(stream->physical, buf, 1);
  625.       if (buf[0] != '\0') __objc_archiving_fatal("Expected null-byte, got opcode %c", buf[0]);
  626.     }
  627.     else if ((buf[0]&_B_CODE) == _B_UCOMM)
  628.     {
  629.       if (key) __objc_archiving_fatal("Cannot register use upcode...",0);
  630.       len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
  631.       (*object) = hash_value_for_key (stream->object_table, (void*)key);
  632.     }
  633.     else if (buf[0] == (_B_EXT | _BX_OBJREF))    /* a forward reference */
  634.     {
  635.       struct objc_list* other;
  636.       len = objc_read_unsigned_int (stream, &key);
  637.       other = (struct objc_list*)hash_value_for_key (stream->object_refs, (void*)key);
  638.       hash_add (&stream->object_refs, (void*)key, (void*)list_cons(object, other));
  639.     }
  640.     else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
  641.     {
  642.       if (key) __objc_archiving_fatal("Cannot register root object...",0);
  643.       len = objc_read_object (stream, object);
  644.       __objc_finish_read_root_object (stream);
  645.     }
  646.     else __objc_archiving_fatal("Expected object, got opcode %c", buf[0]);
  647.   }
  648.   return len;
  649. }
  650.  
  651. static int
  652. objc_read_class (struct objc_typed_stream* stream, OCClass** class)
  653. {
  654.   unsigned char buf[sizeof (unsigned int)];
  655.   int len;
  656.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  657.   {
  658.     unsigned int key = 0;
  659.  
  660.     if ((buf[0]&_B_CODE) == _B_RCOMM)    /* register following */
  661.     {
  662.       len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
  663.       len = (*stream->read)(stream->physical, buf, 1);
  664.     }
  665.  
  666.     if (buf[0] == (_B_EXT | _BX_CLASS))
  667.     {
  668.       char* class_name;
  669.       int version;
  670.  
  671.       /* get class */
  672.       len = objc_read_string (stream, &class_name);
  673.       (*class) = objc_get_class(class_name);
  674.       __objc_xfree (class_name);
  675.  
  676.       /* register */
  677.       if (key) hash_add (&stream->stream_table, (void*)key, *class);
  678.       objc_read_unsigned_int(stream, &version);
  679.       hash_add (&stream->class_table, (*class)->name, (void*)version);
  680.     }
  681.     else if ((buf[0]&_B_CODE) == _B_UCOMM)
  682.     {
  683.       if (key) __objc_archiving_fatal("Cannot register use upcode...",0);
  684.       len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
  685.       (*class) = hash_value_for_key (stream->stream_table, (void*)key);
  686.       if (!*class) __objc_archiving_fatal("Cannot find class for key %x", key);
  687.     }
  688.     else __objc_archiving_fatal("Expected class, got opcode %c", buf[0]);
  689.   }
  690.   return len;
  691. }
  692.  
  693. int
  694. objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
  695. {
  696.   unsigned char buf[sizeof (unsigned int)];
  697.   int len;
  698.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  699.   {
  700.     unsigned int key = 0;
  701.  
  702.     if ((buf[0]&_B_CODE) == _B_RCOMM)    /* register following */
  703.     {
  704.       len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
  705.       len = (*stream->read)(stream->physical, buf, 1);
  706.     }
  707.  
  708.     if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
  709.     {
  710.       char* selector_name;
  711.  
  712.       /* get selector */
  713.       len = objc_read_string (stream, &selector_name);
  714.       (*selector) = sel_get_uid(selector_name);
  715.       __objc_xfree (selector_name);
  716.  
  717.       /* register */
  718.       if (key) hash_add (&stream->stream_table, (void*)key, (unsigned char *)(*selector));
  719.     }
  720.     else if ((buf[0]&_B_CODE) == _B_UCOMM)
  721.     {
  722.       if (key) __objc_archiving_fatal("Cannot register use upcode...",0);
  723.       len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
  724.       (*selector) = hash_value_for_key (stream->stream_table, (void*)key);
  725.     }
  726.     else __objc_archiving_fatal("Expected selector, got opcode %c", buf[0]);
  727.   }
  728.   return len;
  729. }
  730.  
  731.  
  732. static const char*
  733. __objc_skip_type (const char* type)
  734. {
  735.   switch (*type)
  736.   {
  737.     case _C_ID:
  738.     case _C_CLASS:
  739.     case _C_SEL:
  740.     case _C_CHR:
  741.     case _C_UCHR:
  742.     case _C_CHARPTR:
  743.     case _C_ATOM:
  744.     case _C_SHT:
  745.     case _C_USHT:
  746.     case _C_INT:
  747.     case _C_UINT:
  748.     case _C_LNG:
  749.     case _C_ULNG:
  750.     case _C_FLT:
  751.     case _C_DBL:
  752.       return ++type;
  753.       break;
  754.  
  755.     case _C_ARY_B:
  756.       while(isdigit(*++type));
  757.       type = __objc_skip_type(type);
  758.       if (*type == _C_ARY_E) return ++type;
  759.       else __objc_archiving_fatal("Cannot parse typespec: %s", (int)type);
  760.       break;
  761.  
  762.     default:
  763.       fprintf(stderr, "__objc_skip_type: cannot parse typespec: %s\n", type);
  764.       abort();
  765.   }
  766. }
  767.  
  768.  
  769. /*
  770. ** User level functions
  771. */
  772.  
  773. /* Write one object, encoded in TYPE and pointed to by DATA to the typed stream STREAM. */
  774.  
  775. int
  776. objc_write_type(TypedStream* stream, const char* type, const void* data)
  777. {
  778.   switch(*type)
  779.   {
  780.     case _C_ID:
  781.       return objc_write_object (stream, *(id*)data);
  782.       break;
  783.  
  784.     case _C_CLASS:
  785.       return objc_write_class (stream, *(OCClass**)data);
  786.       break;
  787.  
  788.     case _C_SEL:
  789.       return objc_write_selector (stream, *(SEL*)data);
  790.       break;
  791.  
  792.     case _C_CHR:
  793.       return objc_write_char(stream, *(char*)data);
  794.       break;
  795.     
  796.     case _C_UCHR:
  797.       return objc_write_unsigned_char(stream, *(unsigned char*)data);
  798.       break;
  799.  
  800.     case _C_SHT:
  801.       return objc_write_short(stream, *(short*)data);
  802.       break;
  803.  
  804.     case _C_USHT:
  805.       return objc_write_unsigned_short(stream, *(unsigned short*)data);
  806.       break;
  807.  
  808.     case _C_INT:
  809.     case _C_LNG:
  810.       return objc_write_int(stream, *(int*)data);
  811.       break;
  812.  
  813.     case _C_UINT:
  814.     case _C_ULNG:
  815.       return objc_write_unsigned_int(stream, *(unsigned int*)data);
  816.       break;
  817.  
  818.     case _C_CHARPTR:
  819.       return objc_write_string (stream, *(char**)data, strlen(*(char**)data));
  820.       break;
  821.  
  822.     case _C_ATOM:
  823.       return objc_write_string_atomic (stream, *(char**)data, strlen(*(char**)data));
  824.       break;
  825.  
  826.     case _C_ARY_B:
  827.       {
  828.     int len = atoi(type+1);
  829.     while (isdigit(*++type));
  830.     return objc_write_array (stream, type, len, data);
  831.       }
  832.       break; 
  833.  
  834.     default:
  835.       fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
  836.       abort();
  837.   }
  838. }
  839.  
  840.  
  841. /* Read one object, encoded in TYPE and pointed to by DATA to the typed stream STREAM.
  842.    DATA specifies the address of the types to read.  Expected type is checked against
  843.    the type actually present on the stream. */
  844.  
  845. int
  846. objc_read_type(TypedStream* stream, const char* type, void* data)
  847. {
  848.   char c;
  849.   switch(c = *type)
  850.   {
  851.     case _C_ID:
  852.       return objc_read_object (stream, (id*)data);
  853.       break;
  854.  
  855.     case _C_CLASS:
  856.       return objc_read_class (stream, (OCClass**)data);
  857.       break;
  858.  
  859.     case _C_SEL:
  860.       return objc_read_selector (stream, (SEL*)data);
  861.       break;
  862.  
  863.     case _C_CHR:
  864.       return objc_read_char (stream, (char*)data);
  865.       break;
  866.     
  867.     case _C_UCHR:
  868.       return objc_read_unsigned_char (stream, (unsigned char*)data);
  869.       break;
  870.  
  871.     case _C_SHT:
  872.       return objc_read_short (stream, (short*)data);
  873.       break;
  874.  
  875.     case _C_USHT:
  876.       return objc_read_unsigned_short (stream, (unsigned short*)data);
  877.       break;
  878.  
  879.     case _C_INT:
  880.     case _C_LNG:
  881.       return objc_read_int (stream, (int*)data);
  882.       break;
  883.  
  884.     case _C_UINT:
  885.     case _C_ULNG:
  886.       return objc_read_unsigned_int (stream, (unsigned int*)data);
  887.       break;
  888.  
  889.     case _C_CHARPTR:
  890.     case _C_ATOM:
  891.       return objc_read_string (stream, (char**)data);
  892.       break;
  893.  
  894.     case _C_ARY_B:
  895.       {
  896.     int len = atoi(type+1);
  897.     while (isdigit(*++type));
  898.     return objc_read_array (stream, type, len, data);
  899.       }
  900.       break; 
  901.  
  902.     default:
  903.       fprintf(stderr, "objc_read_type: cannot parse typespec: %s\n", type);
  904.       abort();
  905.   }
  906. }
  907.  
  908.  
  909. /* Write the object specified by the template TYPE to STREAM.  Last arguments specify
  910.    addresses of values to be written.  It might seem surprising to specify values by
  911.    address, but this is extremely convenient for copy-paste with objc_read_types calls.
  912.    A more down-to-the-earth cause for this passing of addresses is that values of
  913.    arbitrary size is not well supported in ANSI C for functions with variable number of
  914.    arguments. */
  915.  
  916. int 
  917. objc_write_types (TypedStream* stream, const char* type, ...)
  918. {
  919.   va_list args;
  920.   const char *c;
  921.   int res = 0;
  922.  
  923.   va_start(args, type);
  924.  
  925.   for (c = type; *c; c = __objc_skip_type (c))
  926.   {
  927.     switch(*c)
  928.     {
  929.       case _C_ID:
  930.         res = objc_write_object (stream, *va_arg (args, id*));
  931.     break;
  932.  
  933.       case _C_CLASS:
  934.     res = objc_write_class (stream, *va_arg(args, OCClass**));
  935.     break;
  936.  
  937.       case _C_SEL:
  938.     res = objc_write_selector (stream, *va_arg(args, SEL*));
  939.     break;
  940.     
  941.       case _C_CHR:
  942.     res = objc_write_char (stream, *va_arg (args, char*));
  943.     break;
  944.     
  945.       case _C_UCHR:
  946.     res = objc_write_unsigned_char (stream, *va_arg (args, unsigned char*));
  947.     break;
  948.     
  949.       case _C_SHT:
  950.     res = objc_write_short (stream, *va_arg(args, short*));
  951.     break;
  952.  
  953.       case _C_USHT:
  954.     res = objc_write_unsigned_short (stream, *va_arg(args, unsigned short*));
  955.     break;
  956.  
  957.       case _C_INT:
  958.       case _C_LNG:
  959.     res = objc_write_int(stream, *va_arg(args, int*));
  960.     break;
  961.     
  962.       case _C_UINT:
  963.       case _C_ULNG:
  964.     res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*));
  965.     break;
  966.  
  967.       case _C_CHARPTR:
  968.     {
  969.       char** str = va_arg(args, char**);
  970.       res = objc_write_string (stream, *str, strlen(*str));
  971.     }
  972.     break;
  973.  
  974.       case _C_ATOM:
  975.     {
  976.       char** str = va_arg(args, char**);
  977.       res = objc_write_string_atomic (stream, *str, strlen(*str));
  978.     }
  979.     break;
  980.  
  981.       case _C_ARY_B:
  982.     {
  983.       int len = atoi(c+1);
  984.       const char* t = c;
  985.       while (isdigit(*++t));
  986.       res = objc_write_array (stream, t, len, va_arg(args, void*));
  987.       t = __objc_skip_type (t);
  988.       if (*t != _C_ARY_E) __objc_archiving_fatal("Expected `]', got: %s", (int)t);
  989.     }
  990.     break; 
  991.     
  992.       default:
  993.     fprintf(stderr, "objc_write_types: cannot parse typespec: %s\n", type);
  994.     abort();
  995.     }
  996.   }
  997.   va_end(args);
  998.   return res;
  999. }
  1000.  
  1001.  
  1002. /* Last arguments specify addresses of values to be read.  Expected type
  1003.    is checked against the type actually present on the stream. */
  1004.  
  1005. int 
  1006. objc_read_types(TypedStream* stream, const char* type, ...)
  1007. {
  1008.   va_list args;
  1009.   const char *c;
  1010.   int res = 0;
  1011.  
  1012.   va_start(args, type);
  1013.  
  1014.   for (c = type; *c; c = __objc_skip_type(c))
  1015.   {
  1016.     switch(*c)
  1017.     {
  1018.       case _C_ID:
  1019.         res = objc_read_object(stream, va_arg(args, id*));
  1020.     break;
  1021.  
  1022.       case _C_CLASS:
  1023.     res = objc_read_class(stream, va_arg(args, OCClass**));
  1024.     break;
  1025.  
  1026.       case _C_SEL:
  1027.     res = objc_read_selector(stream, va_arg(args, SEL*));
  1028.     break;
  1029.     
  1030.       case _C_CHR:
  1031.     res = objc_read_char(stream, va_arg(args, char*));
  1032.     break;
  1033.     
  1034.       case _C_UCHR:
  1035.     res = objc_read_unsigned_char(stream, va_arg(args, unsigned char*));
  1036.     break;
  1037.     
  1038.       case _C_SHT:
  1039.     res = objc_read_short(stream, va_arg(args, short*));
  1040.     break;
  1041.  
  1042.       case _C_USHT:
  1043.     res = objc_read_unsigned_short(stream, va_arg(args, unsigned short*));
  1044.     break;
  1045.  
  1046.       case _C_INT:
  1047.       case _C_LNG:
  1048.     res = objc_read_int(stream, va_arg(args, int*));
  1049.     break;
  1050.     
  1051.       case _C_UINT:
  1052.       case _C_ULNG:
  1053.     res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*));
  1054.     break;
  1055.  
  1056.       case _C_CHARPTR:
  1057.       case _C_ATOM:
  1058.     {
  1059.       char** str = va_arg(args, char**);
  1060.       res = objc_read_string (stream, str);
  1061.     }
  1062.     break;
  1063.  
  1064.       case _C_ARY_B:
  1065.     {
  1066.       int len = atoi(c+1);
  1067.       const char* t = c;
  1068.       while (isdigit(*++t));
  1069.       res = objc_read_array (stream, t, len, va_arg(args, void*));
  1070.       t = __objc_skip_type (t);
  1071.       if (*t != _C_ARY_E) __objc_archiving_fatal("Expected `]', got: %s", (int)t);
  1072.     }
  1073.     break; 
  1074.     
  1075.       default:
  1076.     fprintf(stderr, "objc_read_types: cannot parse typespec: %s\n", type);
  1077.     abort();
  1078.     }
  1079.   }
  1080.   va_end(args);
  1081.   return res;
  1082. }
  1083.  
  1084.  
  1085. /* Write an array of COUNT elements of TYPE from the memory address DATA.
  1086.    This is equivalent of objc_write_type (stream, "[N<type>]", data) */
  1087.  
  1088. int
  1089. objc_write_array (TypedStream* stream, const char* type, int count, const void* data)
  1090. {
  1091.   int off = objc_sizeof_type(type);
  1092.   const char* where = data;
  1093.  
  1094.   while (count-- > 0)
  1095.   {
  1096.     objc_write_type(stream, type, where);
  1097.     where += off;
  1098.   }
  1099.   return 1;
  1100. }
  1101.  
  1102.  
  1103. /* Read an array of COUNT elements of TYPE into the memory address DATA.
  1104.    The memory pointed to by data is supposed to be allocated by the callee.
  1105.    This is equivalent of objc_read_type (stream, "[N<type>]", data) */
  1106.  
  1107. int
  1108. objc_read_array (TypedStream* stream, const char* type, int count, void* data)
  1109. {
  1110.   int off = objc_sizeof_type(type);
  1111.   char* where = (char*)data;
  1112.  
  1113.   while (count-- > 0)
  1114.   {
  1115.     objc_read_type(stream, type, where);
  1116.     where += off;
  1117.   }
  1118.   return 1;
  1119. }
  1120.  
  1121.  
  1122. static int 
  1123. __objc_fread(BPTR file, char* data, int len)
  1124. {
  1125.   return FRead(file, data, len, 1);
  1126. }
  1127.  
  1128.  
  1129. static int 
  1130. __objc_fwrite(BPTR file, char* data, int len)
  1131. {
  1132.   return FWrite(file, data, len, 1);
  1133. }
  1134.  
  1135.  
  1136. static int
  1137. __objc_feof(BPTR file)
  1138. {
  1139.   int c;
  1140.   if((c=FGetC(file))==EOF) return 1;
  1141.   UnGetC(file,c);
  1142.   return 0;
  1143. }
  1144.  
  1145.  
  1146. static int 
  1147. __objc_no_write(BPTR file, char* data, int len)
  1148. {
  1149.   __objc_archiving_fatal ("TypedStream not open for writing",0);
  1150. }
  1151.  
  1152.  
  1153. static int 
  1154. __objc_no_read(BPTR file, char* data, int len)
  1155. {
  1156.   __objc_archiving_fatal ("TypedStream not open for reading",0);
  1157. }
  1158.  
  1159.  
  1160. static int
  1161. __objc_read_typed_stream_signature (TypedStream* stream)
  1162. {
  1163.   char buffer[80];
  1164.   int pos = 0;
  1165.   do (*stream->read)(stream->physical, buffer+pos, 1); while (buffer[pos++] != '\0');
  1166.   sscanf (buffer, "GNU TypedStream %d", &stream->version);
  1167.   if (stream->version != OBJC_TYPED_STREAM_VERSION)
  1168.     __objc_archiving_fatal ("Cannot handle TypedStream version %d", stream->version);
  1169.   return 1;
  1170. }
  1171.  
  1172.  
  1173. static int
  1174. __objc_write_typed_stream_signature (TypedStream* stream)
  1175. {
  1176.   char buffer[80];
  1177.   sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
  1178.   stream->version = OBJC_TYPED_STREAM_VERSION;
  1179.   (*stream->write)(stream->physical, buffer, strlen(buffer)+1);
  1180.   return 1;
  1181. }
  1182.  
  1183.  
  1184. static void __objc_finish_write_root_object(struct objc_typed_stream* stream)
  1185. {
  1186.   hash_delete (stream->object_table);
  1187.   stream->object_table = hash_new(64, (hash_func_type)hash_ptr, (compare_func_type)compare_ptrs);
  1188. }
  1189.  
  1190.  
  1191. static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
  1192. {
  1193.   node_ptr node;
  1194.   SEL awake_sel = sel_get_uid ("awake");
  1195.  
  1196.   /* resolve object forward references */
  1197.   for (node = hash_next (stream->object_refs, NULL); node; node = hash_next (stream->object_refs, node))
  1198.   {
  1199.     struct objc_list* reflist = node->value;
  1200.     const void* key = node->key;
  1201.     id object = hash_value_for_key (stream->object_table, key);
  1202.     while(reflist)
  1203.     {
  1204.       *((id*)reflist->head) = object;
  1205.       reflist = reflist->tail;
  1206.     }
  1207.     list_free (node->value);
  1208.   }
  1209.  
  1210.   /* empty object reference table */
  1211.   hash_delete (stream->object_refs);
  1212.   stream->object_refs = hash_new(8, (hash_func_type)hash_ptr, (compare_func_type)compare_ptrs);
  1213.  
  1214.   /* call -awake for all objects read  */
  1215.   if (awake_sel)
  1216.   {
  1217.     for (node = hash_next (stream->object_table, NULL); node; node = hash_next (stream->object_table, node))
  1218.     {
  1219.       id object = node->value;
  1220.       if (__objc_responds_to (object, awake_sel)) (*objc_msg_lookup(object, awake_sel))(object, awake_sel);
  1221.     }
  1222.   }
  1223.  
  1224.   /* empty object table */
  1225.   hash_delete (stream->object_table);
  1226.   stream->object_table = hash_new(64, (hash_func_type)hash_ptr, (compare_func_type)compare_ptrs);
  1227. }
  1228.  
  1229.  
  1230. /* Flush a physical file */
  1231.  
  1232. int __objc_fflush(BPTR fp)
  1233. {
  1234.   if(Flush(fp)) return 0; else return -1;
  1235. }
  1236.  
  1237.  
  1238. /* Open the stream PHYSICAL in MODE */
  1239.  
  1240. TypedStream* 
  1241. objc_amigaopen_typed_stream (BPTR physical, int mode)
  1242. {
  1243.   TypedStream* s = (TypedStream*)__objc_xmalloc(sizeof(TypedStream));
  1244.  
  1245.   s->mode = mode;
  1246.   s->physical = (void *)physical;
  1247.   s->stream_table = hash_new(64, (hash_func_type)hash_ptr, (compare_func_type)compare_ptrs);
  1248.   s->object_table = hash_new(64, (hash_func_type)hash_ptr, (compare_func_type)compare_ptrs);
  1249.   s->eof = (objc_typed_eof_func)__objc_feof;
  1250.   s->flush = (objc_typed_flush_func)__objc_fflush;
  1251.   s->writing_root_p = 0;
  1252.   if (mode == OBJC_READONLY)
  1253.   {
  1254.     s->class_table = hash_new(8, (hash_func_type)hash_string, (compare_func_type)compare_strings);
  1255.     s->object_refs = hash_new(8, (hash_func_type)hash_ptr, (compare_func_type)compare_ptrs);
  1256.     s->read = (objc_typed_read_func)__objc_fread;
  1257.     s->write = (objc_typed_write_func)__objc_no_write;
  1258.     __objc_read_typed_stream_signature (s);
  1259.   }
  1260.   else if (mode == OBJC_WRITEONLY)
  1261.   {
  1262.     s->class_table = 0;
  1263.     s->object_refs = 0;
  1264.     s->read = (objc_typed_read_func)__objc_no_read;
  1265.     s->write = (objc_typed_write_func)__objc_fwrite;
  1266.     __objc_write_typed_stream_signature (s);
  1267.   }      
  1268.   else
  1269.   {
  1270.     objc_close_typed_stream (s);
  1271.     return NULL;
  1272.   }
  1273.   s->type = OBJC_FILE_STREAM;
  1274.   return s;
  1275. }
  1276.  
  1277.  
  1278. /* Open the file named by FILE_NAME in MODE */
  1279.  
  1280. TypedStream*
  1281. objc_open_typed_stream_for_file (const char* file_name, int mode)
  1282. {
  1283.   BPTR file = NULL;
  1284.   TypedStream* s;
  1285.  
  1286.   if (mode == OBJC_READONLY) file = Open ((char *)file_name, MODE_OLDFILE);
  1287.   else file = Open ((char *)file_name, MODE_NEWFILE);
  1288.  
  1289.   if (file)
  1290.   {
  1291.     s = objc_amigaopen_typed_stream (file, mode);
  1292.     if (s) s->type |= OBJC_MANAGED_STREAM;
  1293.     return s;
  1294.   }
  1295.   else return NULL;
  1296. }
  1297.  
  1298.  
  1299. /* Close STREAM freeing the structure it self.  If it was opened with
  1300.    objc_open_typed_stream_for_file, the file will also be closed. */
  1301.  
  1302. void
  1303. objc_close_typed_stream (TypedStream* stream)
  1304. {
  1305.   if (stream->mode == OBJC_READONLY)
  1306.   {
  1307.     __objc_finish_read_root_object (stream); /* Just in case... */
  1308.     hash_delete (stream->class_table);
  1309.     hash_delete (stream->object_refs);
  1310.   }
  1311.  
  1312.   hash_delete (stream->stream_table);
  1313.   hash_delete (stream->object_table);
  1314.  
  1315.   if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM)) Close ((BPTR)stream->physical);
  1316.   __objc_xfree (stream);
  1317. }
  1318.  
  1319.  
  1320. BOOL
  1321. objc_end_of_typed_stream (TypedStream* stream)
  1322. {
  1323.   return (*stream->eof)(stream->physical);
  1324. }
  1325.  
  1326.  
  1327. void
  1328. objc_flush_typed_stream (TypedStream* stream)
  1329. {
  1330.   (*stream->flush)(stream->physical);
  1331. }
  1332.  
  1333.  
  1334. int 
  1335. objc_get_stream_class_version (TypedStream* stream, OCClass* class)
  1336. {
  1337.   if (stream->class_table) return (int) hash_value_for_key (stream->class_table, class->name);
  1338.   else return class_get_version (class);
  1339. }
  1340.